//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<signal.cpp>
///	@path	~/src/lib/system/
///	@date	2007/10/17
///	@desc	Encapsulate signal(event) IPC.

#include "config/config.h"
#include "config/os.h"

#include "lib/system/signal.h"

namespace xeres {

	// create signal object
	Signal::Signal( bool manualReset , bool initSignaled , const WString& name )
	{
		HANDLE hEvent = ::CreateEvent(
			NULL ,
			manualReset ? TRUE : FALSE ,
			initSignaled ? TRUE : FALSE ,
			name.empty() ? NULL : name.c_str() );
		if( hEvent == NULL )
		{
			__win32_error( _S("Signal::CTOR: Failed to create event object: %s.") );
			FATAL_ABORT( _S("Signal creation") );
		}
		m_handle = (void *)hEvent;
	}

	// open exist signal
	Signal::Signal( const WString& name )
	{
		assert( !name.empty() );
		HANDLE hEvent = ::OpenEvent( EVENT_MODIFY_STATE , FALSE , name.c_str() );
		if( hEvent == NULL )
		{
			__win32_error( _S("Signal::CTOR: Failed to open exist event object: %s.") );
			FATAL_ABORT( _S("Signal open") );
		}
		m_handle = (void *)hEvent;
	}

	// copy a signal object
	Signal::Signal( const Signal& rhs )
	{
		HANDLE hProcess = ::GetCurrentProcess();
		HANDLE hEvent = NULL;
		if( ::DuplicateHandle(
			hProcess ,
			(HANDLE)rhs.m_handle ,
			hProcess ,
			&hEvent ,
			0 ,
			FALSE ,
			DUPLICATE_SAME_ACCESS ) == FALSE )
		{
			__win32_error( _S("Signal::CTOR: Failed to duplicate event object: %s.") );
			FATAL_ABORT( _S("Signal duplication") );
		}
		m_handle = (void *)hEvent;
	}

	// dtor
	Signal::~Signal( void )
	{
		if( ::CloseHandle( (HANDLE)m_handle ) == FALSE )
		{
			__win32_error( _S("Signal::DTOR: Failed to close event handle: %s.") );
		}
	}

	// wait
	void Signal::Wait( void )
	{
		::WaitForSingleObject( (HANDLE)m_handle , INFINITE );
	}

	// wait
	bool Signal::Wait( const Time& time )
	{
		return ( ::WaitForSingleObject( (HANDLE)m_handle , (DWORD)time.ToMilliSecond() ) == WAIT_OBJECT_0 );
	}

	// set signaled
	void Signal::SetSignal( void )
	{
		if( ::SetEvent( (HANDLE)m_handle ) == FALSE )
		{
			__win32_error( _S("Signal::signal: Failed to set signal: %s.") );
		}
	}

	// set nonsignaled
	void Signal::Reset( void )
	{
		if( ::ResetEvent( (HANDLE)m_handle ) == FALSE )
		{
			__win32_error( _S("Signal::signal: Failed to reset signal: %s.") );
		}
	}

} // namespace xeres
